package cn.haocxy.jfm.gui;

import java.util.Arrays;
import java.util.Collection;
import java.util.function.Consumer;

import javafx.geometry.Insets;
import javafx.scene.Node;
import javafx.scene.control.ScrollPane;
import javafx.scene.control.ScrollPane.ScrollBarPolicy;
import javafx.scene.input.MouseButton;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.Background;
import javafx.scene.layout.BackgroundFill;
import javafx.scene.layout.CornerRadii;
import javafx.scene.layout.FlowPane;
import javafx.scene.paint.Color;
import cn.haocxy.jfm.filelist.AddEvent;
import cn.haocxy.jfm.filelist.ClearEvent;
import cn.haocxy.jfm.filelist.DoNotSort;
import cn.haocxy.jfm.filelist.FileItem;
import cn.haocxy.jfm.filelist.FileList;
import cn.haocxy.jfm.filelist.Sorter;

/**
 * 显示某一个文件夹的内容，提供对文件夹内容的选取，以及进入子文件夹的功能。
 * 
 * @author 蔡心宇
 *
 */
public final class FileListPane {

	private static final Insets PADDING = new Insets(20);

	private static final double GAP_SIZE = 20;
	
	private final FileList model;

	private final ScrollPane scrollPane = new ScrollPane();
	
	private final FlowPane flowPane = new FlowPane();
	
	private Consumer<String> onInfo = null;

	// 排序方式，默认不排序，直接按照操作系统提供内容的顺序显示
	private Sorter sorter = null;
	
	public FileListPane(FileList model) {
		this.model = model;

		init();
	}
	
	public FileListPane(FileList model, Sorter sorter) {
		this.model = model;
		this.sorter = sorter;
		
		init();
	}
	
	private void init() {
		
		flowPane.setPadding(PADDING);
		flowPane.setVgap(GAP_SIZE);
		flowPane.setHgap(GAP_SIZE);
		scrollPane.setContent(flowPane);

		scrollPane.setHbarPolicy(ScrollBarPolicy.NEVER);
		scrollPane.setVbarPolicy(ScrollBarPolicy.ALWAYS);
		scrollPane.fitToWidthProperty().set(true);
		
		// 下面几行代码使视图背景为白色
		BackgroundFill fill = new BackgroundFill(Color.WHITE, CornerRadii.EMPTY, Insets.EMPTY);
		Background bg = new Background(fill);
		flowPane.setBackground(bg);
		flowPane.minHeightProperty().bind(scrollPane.heightProperty());
		

		model.getAddEventHandlers().addHandler(this::onAdd);
		model.getClearEventHandlers().addHandler(this::onClear);
		model.getDirEventHandlers().addHandler(e->FileItemMenu.hideMenu());
		
		
		flowPane.addEventHandler(MouseEvent.MOUSE_RELEASED, e->{
			if (FileListPaneMenu.get().shown()) {
				FileListPaneMenu.get().hide();
			}
			if (e.getButton().equals(MouseButton.SECONDARY)) {
				FileListPaneMenu.get().show(this, e.getScreenX(), e.getScreenY());
			}
		});
		
		loadModelData();		
	}
	
	public FileList getFileList() {
		return model;
	}
	
	public void setOnInfo(Consumer<String> onInfo) {
		this.onInfo = onInfo;
	}
	
	public void info(String text) {
		if (text == null) {
			text = "";
		}
		if (onInfo != null) {
			onInfo.accept(text);
		}
	}
	
	public void clearInfo() {
		info("");
	}
	
	//     加载模型中的数据，因为在把视图绑定到模型前，模型中触发的事件不会被响应，
	// 所以在构造方法中需要把模型中的数据主动装载到界面中。
	private void loadModelData() {
		addItems(model.getFileItems());
	}
	
	private void onAdd(AddEvent e) {
		addItems(e.getAddedItems());
	}
	
	private void onClear(ClearEvent e) {
		flowPane.getChildren().clear();
	}

	private void addItems(Collection<FileItem> items) {
		Collection<Node> nodes = flowPane.getChildren();
		for (FileItem item : items) {
			nodes.add(new FileItemGUI(this, item).toNode());
		}
		
		// 下面这两行代码的作用是触发只有排序规则变化才重新排序的规则
		Sorter sorter = this.sorter;
		this.sorter = null;
		sort(sorter);
	}
	
	private static FileItemGUI[] convert(Collection<Node> nodes) {
		FileItemGUI[] arr = new FileItemGUI[nodes.size()];
		int i = 0;
		for (Node node : nodes) {
			arr[i++] = (FileItemGUI) node.getUserData();
		}
		return arr;
	}
	
	public void sort(Sorter sorter) {
		
		// 如果排序方式是null或不排序，则直接设置为null，避免执行排序过程
		// 
		// 如果不这样做，当传入的sorter为DoNotSort的对象时，有两方面坏处：
		// 1：要执行一次刷新
		// 2：每次切换路径都要执行一次无作用的排序操作
		if (sorter == null || sorter instanceof DoNotSort) {
			sorter = null;
			this.sorter = null;
			return;
		}
		
		// 排序方式没有改变则什么都不做
		if (this.sorter != null && this.sorter.getClass().equals(sorter.getClass())) {
			return;
		}
		
		if (sorter != null) {
			this.sorter = sorter;
			FileItemGUI[] arr = convert(flowPane.getChildren());
			Arrays.sort(arr, sorter);
			Collection<Node> children = flowPane.getChildren();
			children.clear();
			for (FileItemGUI itemGUI : arr) {
				children.add(itemGUI.toNode());
			}
		}
		
	}
	
	public Node toNode() {
		return scrollPane;
	}

}
